package com.cardcaptorsakura.service.memory;

import com.cardcaptorsakura.model.entity.Memory;
import com.cardcaptorsakura.repository.MemoryRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 向量搜索服务
 * 提供基于向量嵌入的相似性搜索功能
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class VectorSearchService {

    private final MemoryRepository memoryRepository;
    private final RestTemplate restTemplate;

    @Value("${app.embedding.api.url:https://api.openai.com/v1/embeddings}")
    private String embeddingApiUrl;

    @Value("${app.embedding.api.key:}")
    private String embeddingApiKey;

    @Value("${app.embedding.model:text-embedding-ada-002}")
    private String embeddingModel;

    @Value("${app.embedding.dimension:1536}")
    private int embeddingDimension;

    @Value("${app.vector.similarity.threshold:0.7}")
    private double similarityThreshold;

    @Value("${app.vector.search.enabled:true}")
    private boolean vectorSearchEnabled;

    /**
     * 生成文本的向量嵌入
     */
    public List<Double> generateEmbedding(String text) {
        if (!vectorSearchEnabled || text == null || text.trim().isEmpty()) {
            return Collections.emptyList();
        }

        try {
            // 构建请求
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("input", text);
            requestBody.put("model", embeddingModel);

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            if (embeddingApiKey != null && !embeddingApiKey.isEmpty()) {
                headers.setBearerAuth(embeddingApiKey);
            }

            HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestBody, headers);

            // 发送请求
            ResponseEntity<Map> response = restTemplate.postForEntity(embeddingApiUrl, request, Map.class);

            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                Map<String, Object> responseBody = response.getBody();
                List<Map<String, Object>> data = (List<Map<String, Object>>) responseBody.get("data");
                
                if (data != null && !data.isEmpty()) {
                    List<Double> embedding = (List<Double>) data.get(0).get("embedding");
                    log.debug("Generated embedding for text: {} characters", text.length());
                    return embedding;
                }
            }

            log.warn("Failed to generate embedding for text: {} characters", text.length());
            return Collections.emptyList();
        } catch (Exception e) {
            log.error("Error generating embedding for text", e);
            return Collections.emptyList();
        }
    }

    /**
     * 批量生成向量嵌入
     */
    public Map<String, List<Double>> generateEmbeddings(List<String> texts) {
        Map<String, List<Double>> results = new HashMap<>();
        
        if (!vectorSearchEnabled || texts == null || texts.isEmpty()) {
            return results;
        }

        try {
            // 构建批量请求
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("input", texts);
            requestBody.put("model", embeddingModel);

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            if (embeddingApiKey != null && !embeddingApiKey.isEmpty()) {
                headers.setBearerAuth(embeddingApiKey);
            }

            HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestBody, headers);

            // 发送请求
            ResponseEntity<Map> response = restTemplate.postForEntity(embeddingApiUrl, request, Map.class);

            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                Map<String, Object> responseBody = response.getBody();
                List<Map<String, Object>> data = (List<Map<String, Object>>) responseBody.get("data");
                
                if (data != null && data.size() == texts.size()) {
                    for (int i = 0; i < texts.size(); i++) {
                        List<Double> embedding = (List<Double>) data.get(i).get("embedding");
                        results.put(texts.get(i), embedding);
                    }
                    log.debug("Generated {} embeddings", results.size());
                }
            }
        } catch (Exception e) {
            log.error("Error generating batch embeddings", e);
        }

        return results;
    }

    /**
     * 搜索相似记忆
     */
    public List<Memory> searchSimilarMemories(String userId, String query, int limit) {
        if (!vectorSearchEnabled || query == null || query.trim().isEmpty()) {
            return Collections.emptyList();
        }

        try {
            // 生成查询向量
            List<Double> queryEmbedding = generateEmbedding(query);
            if (queryEmbedding.isEmpty()) {
                return Collections.emptyList();
            }

            // 获取用户的所有记忆
            List<Memory> userMemories = memoryRepository.findByUserIdAndDeletedFalse(userId);
            
            // 计算相似度并排序
            List<MemorySimilarity> similarities = userMemories.stream()
                .filter(memory -> memory.getEmbedding() != null && !memory.getEmbedding().isEmpty())
                .map(memory -> {
                    double similarity = calculateCosineSimilarity(queryEmbedding, memory.getEmbedding());
                    return new MemorySimilarity(memory, similarity);
                })
                .filter(ms -> ms.similarity >= similarityThreshold)
                .sorted((a, b) -> Double.compare(b.similarity, a.similarity))
                .limit(limit)
                .collect(Collectors.toList());

            List<Memory> results = similarities.stream()
                .map(ms -> ms.memory)
                .collect(Collectors.toList());

            log.debug("Found {} similar memories for query: {}", results.size(), query);
            return results;
        } catch (Exception e) {
            log.error("Error searching similar memories for user: {}, query: {}", userId, query, e);
            return Collections.emptyList();
        }
    }

    /**
     * 查找相似记忆
     */
    public List<Memory> findSimilarMemories(Memory targetMemory, int limit) {
        if (!vectorSearchEnabled || targetMemory.getEmbedding() == null || targetMemory.getEmbedding().isEmpty()) {
            return Collections.emptyList();
        }

        try {
            // 获取同一用户的所有记忆
            List<Memory> userMemories = memoryRepository.findByUserIdAndDeletedFalse(targetMemory.getUserId());
            
            // 计算相似度并排序
            List<MemorySimilarity> similarities = userMemories.stream()
                .filter(memory -> !memory.getId().equals(targetMemory.getId())) // 排除自己
                .filter(memory -> memory.getEmbedding() != null && !memory.getEmbedding().isEmpty())
                .map(memory -> {
                    double similarity = calculateCosineSimilarity(targetMemory.getEmbedding(), memory.getEmbedding());
                    return new MemorySimilarity(memory, similarity);
                })
                .filter(ms -> ms.similarity >= similarityThreshold)
                .sorted((a, b) -> Double.compare(b.similarity, a.similarity))
                .limit(limit)
                .collect(Collectors.toList());

            List<Memory> results = similarities.stream()
                .map(ms -> ms.memory)
                .collect(Collectors.toList());

            log.debug("Found {} similar memories for memory: {}", results.size(), targetMemory.getId());
            return results;
        } catch (Exception e) {
            log.error("Error finding similar memories for memory: {}", targetMemory.getId(), e);
            return Collections.emptyList();
        }
    }

    /**
     * 基于人格查找相似记忆
     */
    public List<Memory> findSimilarMemoriesByPersona(String personaId, String query, int limit) {
        if (!vectorSearchEnabled || query == null || query.trim().isEmpty()) {
            return Collections.emptyList();
        }

        try {
            // 生成查询向量
            List<Double> queryEmbedding = generateEmbedding(query);
            if (queryEmbedding.isEmpty()) {
                return Collections.emptyList();
            }

            // 获取人格的所有记忆
            List<Memory> personaMemories = memoryRepository.findByPersonaIdAndDeletedFalse(personaId);
            
            // 计算相似度并排序
            List<MemorySimilarity> similarities = personaMemories.stream()
                .filter(memory -> memory.getEmbedding() != null && !memory.getEmbedding().isEmpty())
                .map(memory -> {
                    double similarity = calculateCosineSimilarity(queryEmbedding, memory.getEmbedding());
                    return new MemorySimilarity(memory, similarity);
                })
                .filter(ms -> ms.similarity >= similarityThreshold)
                .sorted((a, b) -> Double.compare(b.similarity, a.similarity))
                .limit(limit)
                .collect(Collectors.toList());

            List<Memory> results = similarities.stream()
                .map(ms -> ms.memory)
                .collect(Collectors.toList());

            log.debug("Found {} similar memories for persona: {}, query: {}", results.size(), personaId, query);
            return results;
        } catch (Exception e) {
            log.error("Error finding similar memories for persona: {}, query: {}", personaId, query, e);
            return Collections.emptyList();
        }
    }

    /**
     * 聚类相似记忆
     */
    public List<MemoryCluster> clusterMemories(String userId, int maxClusters) {
        if (!vectorSearchEnabled) {
            return Collections.emptyList();
        }

        try {
            // 获取用户的所有有向量的记忆
            List<Memory> memories = memoryRepository.findByUserIdAndDeletedFalse(userId).stream()
                .filter(memory -> memory.getEmbedding() != null && !memory.getEmbedding().isEmpty())
                .collect(Collectors.toList());

            if (memories.size() < 2) {
                return Collections.emptyList();
            }

            // 简单的K-means聚类实现
            int k = Math.min(maxClusters, memories.size());
            List<MemoryCluster> clusters = performKMeansClustering(memories, k);

            log.debug("Clustered {} memories into {} clusters for user: {}", memories.size(), clusters.size(), userId);
            return clusters;
        } catch (Exception e) {
            log.error("Error clustering memories for user: {}", userId, e);
            return Collections.emptyList();
        }
    }

    /**
     * 计算余弦相似度
     */
    public double calculateCosineSimilarity(List<Double> vectorA, List<Double> vectorB) {
        if (vectorA == null || vectorB == null || vectorA.size() != vectorB.size()) {
            return 0.0;
        }

        double dotProduct = 0.0;
        double normA = 0.0;
        double normB = 0.0;

        for (int i = 0; i < vectorA.size(); i++) {
            double a = vectorA.get(i);
            double b = vectorB.get(i);
            
            dotProduct += a * b;
            normA += a * a;
            normB += b * b;
        }

        if (normA == 0.0 || normB == 0.0) {
            return 0.0;
        }

        return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
    }

    /**
     * 计算欧几里得距离
     */
    public double calculateEuclideanDistance(List<Double> vectorA, List<Double> vectorB) {
        if (vectorA == null || vectorB == null || vectorA.size() != vectorB.size()) {
            return Double.MAX_VALUE;
        }

        double sum = 0.0;
        for (int i = 0; i < vectorA.size(); i++) {
            double diff = vectorA.get(i) - vectorB.get(i);
            sum += diff * diff;
        }

        return Math.sqrt(sum);
    }

    /**
     * 执行K-means聚类
     */
    private List<MemoryCluster> performKMeansClustering(List<Memory> memories, int k) {
        // 初始化聚类中心
        List<List<Double>> centroids = initializeCentroids(memories, k);
        List<MemoryCluster> clusters = new ArrayList<>();
        
        for (int i = 0; i < k; i++) {
            clusters.add(new MemoryCluster(i, new ArrayList<>(), centroids.get(i)));
        }

        boolean changed = true;
        int maxIterations = 100;
        int iteration = 0;

        while (changed && iteration < maxIterations) {
            changed = false;
            
            // 清空聚类
            for (MemoryCluster cluster : clusters) {
                cluster.memories.clear();
            }

            // 分配记忆到最近的聚类中心
            for (Memory memory : memories) {
                int closestCluster = findClosestCluster(memory.getEmbedding(), centroids);
                clusters.get(closestCluster).memories.add(memory);
            }

            // 更新聚类中心
            for (MemoryCluster cluster : clusters) {
                if (!cluster.memories.isEmpty()) {
                    List<Double> newCentroid = calculateCentroid(cluster.memories);
                    if (!newCentroid.equals(cluster.centroid)) {
                        cluster.centroid = newCentroid;
                        changed = true;
                    }
                }
            }

            iteration++;
        }

        // 移除空聚类
        return clusters.stream()
            .filter(cluster -> !cluster.memories.isEmpty())
            .collect(Collectors.toList());
    }

    /**
     * 初始化聚类中心
     */
    private List<List<Double>> initializeCentroids(List<Memory> memories, int k) {
        List<List<Double>> centroids = new ArrayList<>();
        Random random = new Random();
        
        // 随机选择k个记忆作为初始聚类中心
        Set<Integer> selectedIndices = new HashSet<>();
        while (selectedIndices.size() < k && selectedIndices.size() < memories.size()) {
            selectedIndices.add(random.nextInt(memories.size()));
        }
        
        for (int index : selectedIndices) {
            centroids.add(new ArrayList<>(memories.get(index).getEmbedding()));
        }
        
        return centroids;
    }

    /**
     * 找到最近的聚类中心
     */
    private int findClosestCluster(List<Double> vector, List<List<Double>> centroids) {
        int closestIndex = 0;
        double minDistance = calculateEuclideanDistance(vector, centroids.get(0));
        
        for (int i = 1; i < centroids.size(); i++) {
            double distance = calculateEuclideanDistance(vector, centroids.get(i));
            if (distance < minDistance) {
                minDistance = distance;
                closestIndex = i;
            }
        }
        
        return closestIndex;
    }

    /**
     * 计算聚类中心
     */
    private List<Double> calculateCentroid(List<Memory> memories) {
        if (memories.isEmpty()) {
            return Collections.emptyList();
        }
        
        int dimension = memories.get(0).getEmbedding().size();
        List<Double> centroid = new ArrayList<>(Collections.nCopies(dimension, 0.0));
        
        for (Memory memory : memories) {
            List<Double> embedding = memory.getEmbedding();
            for (int i = 0; i < dimension; i++) {
                centroid.set(i, centroid.get(i) + embedding.get(i));
            }
        }
        
        // 计算平均值
        for (int i = 0; i < dimension; i++) {
            centroid.set(i, centroid.get(i) / memories.size());
        }
        
        return centroid;
    }

    /**
     * 记忆相似度
     */
    private static class MemorySimilarity {
        final Memory memory;
        final double similarity;
        
        MemorySimilarity(Memory memory, double similarity) {
            this.memory = memory;
            this.similarity = similarity;
        }
    }

    /**
     * 记忆聚类
     */
    @lombok.Data
    @lombok.AllArgsConstructor
    public static class MemoryCluster {
        private int id;
        private List<Memory> memories;
        private List<Double> centroid;
        
        /**
         * 获取聚类大小
         */
        public int getSize() {
            return memories.size();
        }
        
        /**
         * 获取聚类的主要主题标签
         */
        public List<String> getMainTopicTags() {
            Map<String, Long> tagCounts = memories.stream()
                .filter(memory -> memory.getTopicTags() != null)
                .flatMap(memory -> memory.getTopicTags().stream())
                .collect(Collectors.groupingBy(tag -> tag, Collectors.counting()));
            
            return tagCounts.entrySet().stream()
                .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
                .limit(5)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
        }
        
        /**
         * 获取聚类的主要情感标签
         */
        public List<String> getMainEmotionTags() {
            Map<String, Long> tagCounts = memories.stream()
                .filter(memory -> memory.getEmotionTags() != null)
                .flatMap(memory -> memory.getEmotionTags().stream())
                .collect(Collectors.groupingBy(tag -> tag, Collectors.counting()));
            
            return tagCounts.entrySet().stream()
                .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
                .limit(5)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
        }
        
        /**
         * 获取聚类的平均重要性
         */
        public double getAverageImportance() {
            return memories.stream()
                .mapToInt(Memory::getImportance)
                .average()
                .orElse(0.0);
        }
    }
}